using System;
using System.Collections;
using System.Data;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.SearchContext;
using PHSRAG.Utility;
using PHSRAG.WebControls;
using Utils = PHSRAG.Insight21.InsightUtilities;

namespace PHSRAG.Insight21.COI
{
    public partial class DelegatesManagement : BasePage
    {
        #region Private Instance Variables 

        private ICachePolicy applicationCachePolicy;
        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Protected Instance variable

        //Expansion Toggler
        protected ExpansionToggler expansionToggler;

        #endregion

        #region Constants

        /// <summary>Default Annunciator title</summary>
        private const string AnnunciatorTitle = "The following error(s) occurred...";

        /// <summary>Unique string(key) to identify or cache the page index </summary>
        private const string DelegateManagementPageIndexKey = "DelegateManagementPageIndexKey_881BB54F-691E-48ef-8E28-82514D6D5DB3";

        /// <summary>Id column(Datkey column) for the data source</summary>
        private string keyField = "DelegateId";

        #endregion

        #region Private Properties

        /// <summary> 
        /// Get the COIUserSummary object relevant to the passed in search criteria.
        /// </summary>
        private COIUserSummary COIUserSummary
        {
            get
            {
                COIUserSummary cOIUserSummary = GetCOIUserSummaryFromCache ?? new COIUserSummary(cachePolicy);
                cOIUserSummary.LoadDelegates(DataAccess.ConnectionString, (supervisor.Items.Count > 0) ? Convert.ToInt32(supervisor.SelectedValue) : -1);
                cOIUserSummary.Cache();
                return cOIUserSummary;
            }
        }

        /// <summary>
        /// Gets the Cached COIUserSummary object
        /// </summary>
        private COIUserSummary GetCOIUserSummaryFromCache
        {
            get { return cachePolicy.GetCachedObject(COIUserSummary.CacheKey) as COIUserSummary; }
        }

        /// <summary>
        /// Gets/Sets the current page within the datagrid for display. This information persists across page loads.
        /// </summary>
        private int CurrentPageIndex
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.DelegateManagementPageKey) as Hashtable;
                return (h == null || h[DelegateManagementPageIndexKey] == null) ? 0 : (int) h[DelegateManagementPageIndexKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.DelegateManagementPageKey) as Hashtable ?? new Hashtable();
                h[DelegateManagementPageIndexKey] = value;
                searchResults.CurrentPageIndex = value;
                pageCachePolicy.Cache(Keys.DelegateManagementPageKey, h);
            }
        }

        #endregion

        #region InitializeComponent for events

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            header.Navigate += OnNavigate;
            breadCrumb.Navigate += OnNavigate;
            coiAdminSubNavigation.Navigate += OnNavigate;
            Load += OnPageLoad;
            topPager.FirstPage += OnFirstPage;
            topPager.PreviousPage += OnPreviousPage;
            topPager.NextPage += OnNextPage;
            topPager.LastPage += OnLastPage;
            searchResults.ItemCreated += OnItemCreated;
            searchResults.PageIndexChanged += OnPageIndexChanged;
            searchResults.SortCommand += OnSort;
            bottomPager.FirstPage += OnFirstPage;
            bottomPager.PreviousPage += OnPreviousPage;
            bottomPager.NextPage += OnNextPage;
            bottomPager.LastPage += OnLastPage;
        }

        #endregion

        #region EventHandlers

        protected void OnPageLoad(object sender, EventArgs e)
        {
            try
            {
                annunciator.Message = string.Empty;
                annunciator.Title = string.Empty;
                breadCrumb.Add("Delegate Management", Settings.GetKeyValue("SubNavigation.CoI.DelegatesManagementURL", ""), Settings.GetKeyValue("BreadCrumb.SummaryPageLevel", 1));
                ClientScript.GetPostBackEventReference(this, string.Empty);

                if (IsPostBack)
                {
                    string eventTarget = Request["__EVENTTARGET"] ?? string.Empty;

                    if (eventTarget == "ChildWindowPostBack")
                    {
                        CurrentPageIndex = 0;
                        LoadDataGrid();
                    }
                }

                if (!IsPostBack && postbackGuard.IsValid)
                {
                    searchResults.PageSize = Settings.GetKeyValue("COIDataGrid.ItemsPerPage", 20);
                    CommonSearchContext searchContext = cachePolicy.GetCachedObject(CommonSearchContext.CacheKey) as CommonSearchContext;
                    gridContainer.Visible = false;
                    DataTable dt = COIUserSummary.GetInstitutionOrUnitDepartment(DataAccess.ConnectionString, 0);
                    if (dt != null)
                    {
                        DataRow dr = dt.NewRow();
                        dr["Id"] = -1;
                        dr["Name"] = "--Select--";
                        dt.Rows.InsertAt(dr, 0);
                    }
                    organization.DataSource = dt;
                    organization.DataValueField = "Id";
                    organization.DataTextField = "Name";
                    organization.DataBind();
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        protected override void OnInit(EventArgs e)
        {
            InitializeComponent();
            base.OnInit(e);
            cachePolicy = (ICachePolicy) Session[Names.CachePolicyKey];
            pageCachePolicy = (ICachePolicy) Session[Names.PageCachePolicyKey];
            applicationCachePolicy = (ICachePolicy) Application[Names.ApplicationCachePolicyKey];
            //coiSubNavigation.Navigate += new CommandEventHandler(OnSubNavigate);     
        }

        /// <summary>
        /// Handler for event raised while each data grid item is created.
        /// If the item being created is the data grid header, do the following:
        /// Add the appropriate sort symbol to denote ascending/descending sequence for the current sort column.
        /// This requires us to locate the cell which corresponding to the column within the collection of TableCell
        /// maintained by the DataGridItem which is under creation. That collection is indexed numerically, the value being
        /// the position of the column within the columns collection maintained by the data grid.
        /// One simple way to do this is to create static mapping between the name of the column and its index. However, this
        /// suffers from the shortcoming that if the sequence of columns is changed on the page, the static binding MUST
        /// be changed too. If they get out of sync, we would be sorting on inappropriate columns!
        /// To avoid this, and to render the code independent of how the page gets managed, we will build a Hashtable of
        /// column indeces, keyed by the sort expression of each column. That way, we could do a quick lookup to get the
        /// index of a column and set the sort symbol on that column.
        /// If the item being created is a data row item, disable its view state.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnItemCreated(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Header)
                {
                    COIUserSummary cOIUserSummary = GetCOIUserSummaryFromCache;
                    Label sortSymbol = new Label();
                    sortSymbol.Text = (cOIUserSummary.SortAscending) ? InsightUtilities.Constants.SortAscendingText : InsightUtilities.Constants.SortDescendingText;
                    sortSymbol.Font.Name = InsightUtilities.Constants.SortSymbolFontName;

                    Hashtable columnMap = new Hashtable();
                    foreach (DataGridColumn column in searchResults.Columns)
                    {
                        columnMap[column.SortExpression] = searchResults.Columns.IndexOf(column);
                    }

                    string sortColumn = cOIUserSummary.SortColumn;
                    if (columnMap.ContainsKey(sortColumn))
                    {
                        e.Item.Cells[(int) columnMap[sortColumn]].Controls.Add(sortSymbol);
                    }
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link(s) before the 
        /// header breadcrumb navigates.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                PurgeCache();
                coiSubNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        ///// <summary>
        ///// Purges the cache before the COI subnavigation header performs a redirect.
        ///// </summary>
        ///// <param name="sender">Control which rasied the event.</param>
        ///// <param name="e">Arguments associated with the event.</param>
        //private void OnSubNavigate(object sender, CommandEventArgs e)
        //{
        //    try
        //    {
        //        PurgeCache();
        //    }
        //    catch (Exception ex)
        //    {
        //        DisplayExceptionReport(ex);
        //    }
        //}
        /// <summary>
        ///  Make the "Add Delegates" button visble upon selecting a supervisor from the drop down.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnSelectedIndexChanged(object sender, EventArgs e)
        {
            addDelegate.Visible = (Convert.ToInt32(supervisor.SelectedItem.Value) != -1) ? true : false;
        }

        /// <summary>
        /// Handles events raised by sorting the datagrid.
        /// </summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnSort(object source, DataGridSortCommandEventArgs e)
        {
            try
            {
                if (e.SortExpression != string.Empty)
                {
                    COIUserSummary cOIUserSummary = GetCOIUserSummaryFromCache ?? new COIUserSummary(cachePolicy);

                    cOIUserSummary.SortColumn = e.SortExpression;
                    cOIUserSummary.SortAscending = (cOIUserSummary.SortColumn == e.SortExpression) ? !cOIUserSummary.SortAscending : cOIUserSummary.SortAscending;
                    cOIUserSummary.Cache();
                    CurrentPageIndex = 0;
                    LoadDataGrid();
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// This event is raised when the page index property is changed on the pager control.
        /// The page's DataGrid is reloaded with the data belonging to page specified by the index.
        /// </summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnPageIndexChanged(object source, DataGridPageChangedEventArgs e)
        {
            try
            {
                searchResults.CurrentPageIndex = e.NewPageIndex;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Initiates the search by calling PerformSearch
        /// </summary>
        /// <param name="args">Argument associated with the event (contains the search criteria dictionary)</param>
        protected void OnSearch(SearchCriteriaArgs args)
        {
            PerformSearch();
        }

        protected void OnClearSelection(object sender, CommandEventArgs e)
        {
            userName.Text = string.Empty;
            lastName.Text = string.Empty;
            firstName.Text = string.Empty;
            organization.SelectedIndex = -1;
            searchResults.DataSource = null;
            searchResults.DataBind();
            ClearUnitDept();
            addDelegate.Visible = removeSelectedDelegate.Visible = gridContainer.Visible = false;
        }


        /// <summary>
        /// Occurs when the FirstPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the first page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnFirstPage(object sender, CommandEventArgs e)
        {
            try
            {
                CurrentPageIndex = 0;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Occurs when the LastPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the last page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnLastPage(object sender, CommandEventArgs e)
        {
            try
            {
                int lastPageIndex = topPager.PageCount - 1;
                CurrentPageIndex = lastPageIndex;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Occurs when the NextPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the next page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnNextPage(object sender, CommandEventArgs e)
        {
            try
            {
                ++CurrentPageIndex;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Occurs when the PreviousPage hyperlink is clicked on the pager.
        /// The page's DataGrid is reloaded with the data belonging to the previous page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnPreviousPage(object sender, CommandEventArgs e)
        {
            try
            {
                --CurrentPageIndex;
                LoadDataGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }


        protected void OnFetchDelegates(object sender, ImageClickEventArgs e)
        {
            try
            {
                CurrentPageIndex = 0;
                LoadDataGrid();
                if (supervisor.Items.Count > 0 && Convert.ToInt32(supervisor.SelectedValue) != 0)
                {
                    addDelegate.Visible = (Convert.ToInt32(supervisor.SelectedItem.Value) != -1) ? true : false;
                    //Set the Person id in incoming cache.
                    Hashtable outgoingData = new Hashtable();
                    outgoingData.Add(Keys.SupervisorIdKey, Convert.ToInt32(supervisor.SelectedValue));
                    pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        protected void OnOrganizationSelectionChanged(object sender, EventArgs e)
        {
            PopulateDeptUnit();
        }

        protected void OnRemoveSelectedDelegate(object sender, ImageClickEventArgs e)
        {
            try
            {
                ArrayList delegatesMarkedForRemoval = new ArrayList();
                foreach (DataGridItem item in searchResults.Items)
                {
                    if ((item.ItemType == ListItemType.Item || item.ItemType == ListItemType.AlternatingItem)
                        && ((CheckBox) (item.Cells[(int) ColumnIndex.RemoveDelegateCheckBox]).Controls[1]).Checked)
                    {
                        if (((Label) (item.Cells[(int) ColumnIndex.DelagateId]).Controls[1]).Text != string.Empty)
                        {
                            delegatesMarkedForRemoval.Add(((Label) (item.Cells[(int) ColumnIndex.DelagateId]).Controls[1]).Text);
                        }
                    }
                }
                COIUserSummary cOIUserSummary = GetCOIUserSummaryFromCache;

                if (cOIUserSummary != null)
                {
                    if (delegatesMarkedForRemoval.Count > 0)
                    {
                        cOIUserSummary.RemoveDelegate(DataAccess.ConnectionString, delegatesMarkedForRemoval, Convert.ToInt32(supervisor.SelectedValue));
                        CurrentPageIndex = 0;
                        LoadDataGrid();
                    }
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        #endregion

        #region private methods

        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = AnnunciatorTitle;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
        }

        /// <summary>
        /// Retrieves the CommonSearchContext from the cache and
        /// performs a User search through the system.
        /// </summary>
        private void PerformSearch()
        {
            try
            {
                DataTable dt = COIUserSummary.GetSupervisorsByOrganization(
                    DataAccess.ConnectionString, (organization.SelectedIndex == 0) ? 0 : Convert.ToInt32(organization.SelectedValue)
                    , (deptUnit.SelectedIndex == -1) ? string.Empty : GetConcatenatedListOfSelectedDept()
                    , lastName.Text.Trim('*')
                    , firstName.Text.Trim('*')
                    , userName.Text.Trim('*'));

                if (dt != null && dt.Rows.Count > 0)
                {
                    DataRow dr = dt.NewRow();
                    dr["PersonId"] = -1;
                    dr["Name"] = "--Select--";
                    dt.Rows.InsertAt(dr, 0);
                    supervisor.DataSource = dt;
                    supervisor.DataTextField = "Name";
                    supervisor.DataValueField = "PersonId";
                    supervisor.DataBind();
                    supervisor.SelectedValue = "-1";
                }
                else
                {
                    supervisor.DataSource = dt;
                    supervisor.DataTextField = "Name";
                    supervisor.DataValueField = "PersonId";
                    supervisor.DataBind();
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Get the concatenated list of departments/unit selected
        /// </summary>
        private string GetConcatenatedListOfSelectedDept()
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                foreach (ListItem li in deptUnit.Items)
                {
                    if (li.Selected)
                    {
                        sb.Append(li.Value + ",");
                    }
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
            return (sb.ToString() == string.Empty) ? string.Empty : sb.ToString().TrimEnd(',');
        }

        /// <summary>
        /// Loads the COIUser details only for those to displayed on the page.
        /// </summary>
        private void LoadDataGrid()
        {
            try
            {
                COIUserSummary cOIUserSummary = COIUserSummary;
                if (cOIUserSummary != null && cOIUserSummary.GetDataContainer() != null)
                {
                    searchResults.VirtualItemCount = bottomPager.RecordCount =
                        topPager.RecordCount = cOIUserSummary.Count;
                    int currentPageIndex = CurrentPageIndex;
                    int pageCount = (topPager.RecordCount/searchResults.PageSize) +
                        (((topPager.RecordCount%searchResults.PageSize) == 0) ? 0 : 1);
                    bottomPager.PageCount = topPager.PageCount = pageCount;
                    bottomPager.CurrentPage = topPager.CurrentPage = currentPageIndex + 1;

                    DataTable table = cOIUserSummary.GetSummaryList(
                        currentPageIndex*searchResults.PageSize, searchResults.PageSize, DataAccess.ConnectionString, (int) Constants.SourcePage.DelegateManagementPage);
                    searchResults.DataSource = table;
                    searchResults.DataKeyField = keyField;
                    searchResults.DataBind();

                    if (table.Rows.Count == 0)
                    {
                        gridContainer.Visible = false;
                        annunciator.Message = "The search criteria yielded no results.";
                        removeSelectedDelegate.Visible = false;
                    }
                    else
                    {
                        gridContainer.Visible = true;
                        annunciator.Message = string.Empty;
                        ManagePagination();
                        ManageNavigationLinks();
                        removeSelectedDelegate.Visible = true;
                    }
                }
                else
                {
                    searchResults.DataSource = null;
                    searchResults.DataBind();
                    gridContainer.Visible = false;
                    annunciator.Message = "The search criteria yielded no results.";
                }
            }
            catch (Exception ex)
            {
                ExceptionReport.WriteToEventLog("Error occurred while trying to load the search results(Error occured at AddCOIUser.LoadDataGrid())", ex, true, ExceptionReport.ReportType.Error);
                annunciator.Message = "Error occurred while trying to load the search results";
            }
        }

        /// <summary>
        /// Initilize the first record, last record and current page values for the pager controls.
        /// Set the current page index to 0 and manage navigation links.
        /// </summary>
        private void InitializePager()
        {
            bottomPager.FirstRecord = topPager.FirstRecord = 1;
            bottomPager.LastRecord = topPager.LastRecord =
                Math.Min(searchResults.PageSize, searchResults.Items.Count);
            bottomPager.CurrentPage = topPager.CurrentPage = 1;
            CurrentPageIndex = 0;
            ManageNavigationLinks();
        }

        /// <summary>
        /// Enables or Disables links to other pages within the grid.
        /// </summary>
        private void ManageNavigationLinks()
        {
            bottomPager.EnableFirstPage = topPager.EnableFirstPage =
                bottomPager.EnablePreviousPage = topPager.EnablePreviousPage =
                    (searchResults.CurrentPageIndex != 0);

            bottomPager.EnableLastPage = topPager.EnableLastPage =
                bottomPager.EnableNextPage = topPager.EnableNextPage =
                    (searchResults.CurrentPageIndex != (topPager.PageCount - 1));
        }

        /// <summary>
        /// Pagination management.
        /// </summary>
        private void ManagePagination()
        {
            int currentPageIndex = CurrentPageIndex;
            searchResults.CurrentPageIndex = currentPageIndex;

            int startIndex = currentPageIndex*searchResults.PageSize;
            bottomPager.FirstRecord = topPager.FirstRecord = startIndex + 1;

            int lastRecord = COIUserSummary.Count;
            bottomPager.LastRecord = topPager.LastRecord =
                Math.Min(startIndex + searchResults.PageSize, lastRecord);
        }


        /// <summary>
        /// Uncaches all objects with data for this page.
        /// </summary>
        private void PurgeCache()
        {
            System.Diagnostics.Trace.WriteLine("Purging delegate managment summary...");
            COIUserSummary coiUserSummary = GetCOIUserSummaryFromCache;
            if (coiUserSummary != null)
            {
                coiUserSummary.Purge();
                cachePolicy.UnCache(COIUserSummary.CacheKey);
            }
        }

        /// <summary>
        /// Populate the Dept/unit dropdown corresponding to the institution selected
        /// </summary>
        private void PopulateDeptUnit()
        {
            try
            {
                deptUnit.DataSource =
                    COIUserSummary.GetInstitutionOrUnitDepartment(DataAccess.ConnectionString, Convert.ToInt32(organization.SelectedValue));
                deptUnit.DataTextField = "Name";
                deptUnit.DataValueField = "Id";
                deptUnit.DataBind();

                supervisor.Items.Clear();
                searchResults.DataSource = null;
                searchResults.DataBind();
                gridContainer.Visible = false;
                addDelegate.Visible = removeSelectedDelegate.Visible = false;
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Clear the unit/Dept listbox and the supervisor dropdown
        /// </summary>
        private void ClearUnitDept()
        {
            deptUnit.Items.Clear();
            ClearSupervisorDropdown();
        }

        /// <summary>
        /// Clear the entries in the supervisor dropdown
        /// </summary>
        private void ClearSupervisorDropdown()
        {
            supervisor.Items.Clear();
        }

        #endregion

        #region ColumnIndex Enum

        /// <summary>
        /// Provides indexes used in the datagrid for specific columns
        /// </summary>
        private enum ColumnIndex
        {
            /// <summary>DelagateId column index (hidden)</summary>
            DelagateId,
            /// <summary>Name column index (hidden)</summary>
            Name,
            /// <summary>UserName column index (hidden)</summary>
            UserName,
            /// <summary>Organization Fully Qualified Name column index (hidden)</summary>
            OrganizationFullName,
            /// <summary>removeDelagateCheckBox Name column index (hidden)</summary>
            RemoveDelegateCheckBox
        }

        #endregion
    }
}